/*-------------------------------------------------
 *
 * OrbitsWriter - An Offline Blog Writer
 *
 * Copyright (C) 2016  devbean@galaxyworld.org
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *-------------------------------------------------*/

#include "appcontext.h"
#include "document/markupbuilder.h"
#include "mainwindow.h"
#include "previewer.h"
#include "sourceeditor.h"
#include "visualeditor.h"

#include <QAction>
#include <QApplication>
#include <QClipboard>
#include <QCloseEvent>
#include <QDebug>
#include <QLineEdit>
#include <QMenuBar>
#include <QMimeData>
#include <QTabWidget>
#include <QToolBar>
#include <QVBoxLayout>

using namespace Core;
using namespace Core::Internal;

//---------- MainWindowPrivate ----------//

MainWindowPrivate::MainWindowPrivate(MainWindow *win)
    : QObject(win),
      q(win)
{
    setupFileActions();
    setupEditActions();
    setupTextActions();
    setupToolsActions();
    setupHelpActions();
    setupEditorPane();

    connect(AppContext::instance(), &AppContext::appContextStarted,
            this, &MainWindowPrivate::onAppContextStarted);
}

void MainWindowPrivate::onAppContextStarted()
{
    auto builders = AppContext::instance()->builders();
    for (auto builder : builders) {
         appendSourceEditor(builder);
    }
}

void MainWindowPrivate::setupFileActions()
{
    QToolBar *toolbar = q->addToolBar(tr("File"));
    QMenu *menu = q->menuBar()->addMenu(tr("&File"));

    const QIcon newIcon = QIcon::fromTheme("document-new", QIcon(":/icon/new"));
    newAction = menu->addAction(newIcon,  tr("&New"), q, [&] () {

    }, QKeySequence::New);
    newAction->setPriority(QAction::LowPriority);
    toolbar->addAction(newAction);

    const QIcon openIcon = QIcon::fromTheme("document-open", QIcon(":/icon/open"));
    openAction = menu->addAction(openIcon,  tr("&Open..."), q, [&] () {

    }, QKeySequence::Open);
    menu->addSeparator();
    toolbar->addAction(openAction);

    const QIcon saveIcon = QIcon::fromTheme("document-save", QIcon(":/icon/save"));
    saveAction = menu->addAction(saveIcon,  tr("&Save"), q, [&] () {

    }, QKeySequence::Save);
    saveAction->setEnabled(false);
    saveAction->setPriority(QAction::LowPriority);
    toolbar->addAction(saveAction);

    saveAsAction = menu->addAction(tr("Save &As..."), q, [&] () {

    }, QKeySequence::SaveAs);
    saveAsAction->setPriority(QAction::LowPriority);
    menu->addSeparator();

    exitAction = menu->addAction(tr("&Quit"), q, &QWidget::close, QKeySequence::Quit);
}

void MainWindowPrivate::setupEditActions()
{
    QToolBar *toolbar = q->addToolBar(tr("Edit"));
    QMenu *menu = q->menuBar()->addMenu(tr("&Edit"));

    const QIcon undoIcon = QIcon::fromTheme("edit-undo", QIcon(":/icon/undo"));
    undoAction = menu->addAction(undoIcon, tr("&Undo"), q, [&] () {

    }, QKeySequence::Undo);
    toolbar->addAction(undoAction);

    const QIcon redoIcon = QIcon::fromTheme("edit-redo", QIcon(":/icon/redo"));
    redoAction = menu->addAction(redoIcon, tr("&Redo"), q, [&] () {

    }, QKeySequence::Redo);
    redoAction->setPriority(QAction::LowPriority);
    toolbar->addAction(redoAction);
    menu->addSeparator();

#ifndef QT_NO_CLIPBOARD
    const QIcon cutIcon = QIcon::fromTheme("edit-cut", QIcon(":/icon/cut"));
    cutAction = menu->addAction(cutIcon, tr("Cu&t"), q, [&] () {

    }, QKeySequence::Cut);
    cutAction->setPriority(QAction::LowPriority);
    toolbar->addAction(cutAction);

    const QIcon copyIcon = QIcon::fromTheme("edit-copy", QIcon(":/icon/copy"));
    copyAction = menu->addAction(copyIcon, tr("&Copy"), q, [&] () {

    }, QKeySequence::Copy);
    copyAction->setPriority(QAction::LowPriority);
    toolbar->addAction(copyAction);

    const QIcon pasteIcon = QIcon::fromTheme("edit-paste", QIcon(":/icon/paste"));
    pasteAction = menu->addAction(pasteIcon, tr("&Paste"), q, [&] () {

    }, QKeySequence::Paste);
    pasteAction->setPriority(QAction::LowPriority);
    toolbar->addAction(pasteAction);

    if (const QMimeData *mimedata = QApplication::clipboard()->mimeData()) {
        pasteAction->setEnabled(mimedata->hasText());
    }
#endif
}

void MainWindowPrivate::setupTextActions()
{
    QToolBar *toolbar = q->addToolBar(tr("Format"));
    QMenu *menu = q->menuBar()->addMenu(tr("F&ormat"));

    const QIcon boldIcon = QIcon::fromTheme("format-text-bold", QIcon(":/icon/font_bold"));
    textBoldAction = menu->addAction(boldIcon, tr("&Bold"), q, [&] () {
        visualEditor->setTextBold(textBoldAction->isChecked());
    }, QKeySequence::Bold);
    QFont bold;
    bold.setBold(true);
    textBoldAction->setFont(bold);
    textBoldAction->setPriority(QAction::LowPriority);
    textBoldAction->setCheckable(true);
    toolbar->addAction(textBoldAction);

    const QIcon italicIcon = QIcon::fromTheme("format-text-italic", QIcon(":/icon/font_italic"));
    textItalicAction = new QAction(q);
    textItalicAction = menu->addAction(italicIcon, tr("&Italic"), q, [&] () {
        visualEditor->setTextItalic(textItalicAction->isChecked());
    }, QKeySequence::Italic);
    QFont italic;
    italic.setItalic(true);
    textItalicAction->setFont(italic);
    textItalicAction->setPriority(QAction::LowPriority);
    textItalicAction->setCheckable(true);
    toolbar->addAction(textItalicAction);

    const QIcon underlineIcon = QIcon::fromTheme("format-text-underline", QIcon(":/icon/font_underline"));
    textUnderlineAction = menu->addAction(underlineIcon, tr("&Underline"), q, [&] () {
        visualEditor->setTextUnderline(textUnderlineAction->isChecked());
    }, QKeySequence::Underline);
    QFont underline;
    underline.setUnderline(true);
    textUnderlineAction->setFont(underline);
    textUnderlineAction->setPriority(QAction::LowPriority);
    textUnderlineAction->setCheckable(true);
    toolbar->addAction(textUnderlineAction);

    const QIcon strikeoutIcon = QIcon::fromTheme("format-text-strikethrough", QIcon(":/icon/font_strikeout"));
    textStrikeoutAction = menu->addAction(strikeoutIcon, tr("Strike Out"), q, [&] () {
        visualEditor->setTextStrikeOut(textStrikeoutAction->isChecked());
    });
    QFont strikeout;
    strikeout.setStrikeOut(true);
    textStrikeoutAction->setFont(strikeout);
    textStrikeoutAction->setPriority(QAction::LowPriority);
    textStrikeoutAction->setCheckable(true);
    menu->addSeparator();
    toolbar->addAction(textStrikeoutAction);
    toolbar->addSeparator();

    textColorAction = menu->addAction(QIcon(":/icon/font_color"), tr("Text Color"), q, [&] () {

    });
    toolbar->addAction(textColorAction);

    textBackgroundColorAction = menu->addAction(QIcon(":/icon/font_background_color"), tr("Text Background Color"), q, [&] () {

    });
    menu->addSeparator();
    toolbar->addAction(textBackgroundColorAction);
    toolbar->addSeparator();

    const QIcon fillIcon = QIcon::fromTheme("format-justify-fill", QIcon(":/icon/align_justify"));
    alignJustifyAction = new QAction(q);
    alignJustifyAction->setText(tr("Align &Justify"));
    alignJustifyAction->setIcon(fillIcon);
    alignJustifyAction->setShortcut(Qt::CTRL + Qt::Key_J);
    alignJustifyAction->setCheckable(true);
    alignJustifyAction->setPriority(QAction::LowPriority);

    const QIcon centerIcon = QIcon::fromTheme("format-justify-center", QIcon(":/icon/align_center"));
    alignCenterAction = new QAction(q);
    alignCenterAction->setText(tr("Align C&enter"));
    alignCenterAction->setIcon(centerIcon);
    alignCenterAction->setShortcut(Qt::CTRL + Qt::Key_E);
    alignCenterAction->setCheckable(true);
    alignCenterAction->setPriority(QAction::LowPriority);

    const QIcon leftIcon = QIcon::fromTheme("format-justify-left", QIcon(":/icon/align_left"));
    alignLeftAction = new QAction(q);
    alignLeftAction->setText(tr("Align &Left"));
    alignLeftAction->setIcon(leftIcon);
    alignLeftAction->setShortcut(Qt::CTRL + Qt::Key_L);
    alignLeftAction->setCheckable(true);
    alignLeftAction->setPriority(QAction::LowPriority);

    const QIcon rightIcon = QIcon::fromTheme("format-justify-right", QIcon(":/icon/align_right"));
    alignRightAction = new QAction(q);
    alignRightAction->setText(tr("Align &Right"));
    alignRightAction->setIcon(rightIcon);
    alignRightAction->setShortcut(Qt::CTRL + Qt::Key_R);
    alignRightAction->setCheckable(true);
    alignRightAction->setPriority(QAction::LowPriority);

    // Make sure the alignLeft  is always left of the alignRight
    QActionGroup *alignGroup = new QActionGroup(q);
    connect(alignGroup, &QActionGroup::triggered, this, &MainWindowPrivate::textAlign);

    if (QApplication::isLeftToRight()) {
        alignGroup->addAction(alignLeftAction);
        alignGroup->addAction(alignCenterAction);
        alignGroup->addAction(alignRightAction);
    } else {
        alignGroup->addAction(alignRightAction);
        alignGroup->addAction(alignCenterAction);
        alignGroup->addAction(alignLeftAction);
    }
    alignGroup->addAction(alignJustifyAction);

    toolbar->addActions(alignGroup->actions());
    menu->addActions(alignGroup->actions());

    menu->addSeparator();

    bulletListAction = menu->addAction(QIcon(":/icon/ul"), tr("Bullet List"), q, [&] () {

    });
    toolbar->addAction(bulletListAction);

    numberingListAction = menu->addAction(QIcon(":/icon/ol"), tr("Numbering List"), q, [&] () {

    });
    toolbar->addAction(numberingListAction);
}

void MainWindowPrivate::setupToolsActions()
{
    QMenu *menu = q->menuBar()->addMenu(tr("&Tools"));

    settingsAction = menu->addAction(QIcon(":/icon/settings"), tr("Settings"), q, [&] () {

    }, QKeySequence::Preferences);
}

void MainWindowPrivate::setupHelpActions()
{
    QMenu *menu = q->menuBar()->addMenu(tr("&Help"));

    helpAction = menu->addAction(QIcon(":/icon/help"), tr("Help"), q, [&] () {

    }, QKeySequence::HelpContents);
    aboutAction = menu->addAction(tr("About"), q, [&] () {

    });
}

void MainWindowPrivate::setupEditorPane()
{
    QWidget *editorPane = new QWidget(q);
    q->setCentralWidget(editorPane);

    QVBoxLayout *mainLayout = new QVBoxLayout;

    QLineEdit *titleEdit = new QLineEdit(editorPane);
    QFont titleFont;
    titleFont.setPointSize(20);
    titleEdit->setFont(titleFont);
    titleEdit->setStyleSheet("border: 1px solid gray; padding:0 4px;");
    mainLayout->addWidget(titleEdit);

    editorTab = new QTabWidget(editorPane);
    visualEditor = new VisualEditor(editorTab);
    editorTab->addTab(visualEditor, tr("Visual"));
    connect(visualEditor, &VisualEditor::fontChanged, [&] (const QFont &font) {
        textBoldAction->setChecked(font.bold());
        textItalicAction->setChecked(font.italic());
        textUnderlineAction->setChecked(font.underline());
        textStrikeoutAction->setChecked(font.strikeOut());
    });
    connect(visualEditor, &VisualEditor::colorChanged, [&] (const QColor &color) {

    });
    connect(visualEditor, &VisualEditor::alignmentChanged, [&] (Qt::Alignment &alignment) {
        if (alignment & Qt::AlignLeft) {
            alignLeftAction->setChecked(true);
        } else if (alignment & Qt::AlignHCenter) {
            alignCenterAction->setChecked(true);
        } else if (alignment & Qt::AlignRight) {
            alignRightAction->setChecked(true);
        } else if (alignment & Qt::AlignJustify) {
            alignJustifyAction->setChecked(true);
        }
    });

    previewer = new Previewer(editorTab);
    editorTab->addTab(previewer, tr("Preview"));

    mainLayout->addWidget(editorTab);

    editorPane->setLayout(mainLayout);

    connect(editorTab, &QTabWidget::currentChanged, [&] (int) {
        SourceEditor *srcEditor = qobject_cast<SourceEditor *>(editorTab->currentWidget());
        if (srcEditor) {
            srcEditor->updateSource(visualEditor->document());
        }
    });
}

void MainWindowPrivate::appendSourceEditor(MarkupBuilder *builder)
{
    SourceEditor *sourceEditor = new SourceEditor(builder, editorTab);
    editorTab->addTab(sourceEditor, builder->markupName());
}

void MainWindowPrivate::textAlign(QAction *action)
{
    if (action == alignLeftAction) {
        visualEditor->setAlignment(Qt::AlignLeft | Qt::AlignAbsolute);
    } else if (action == alignCenterAction) {
        visualEditor->setAlignment(Qt::AlignHCenter);
    } else if (action == alignRightAction) {
        visualEditor->setAlignment(Qt::AlignRight | Qt::AlignAbsolute);
    } else if (action == alignJustifyAction) {
        visualEditor->setAlignment(Qt::AlignJustify);
    }
}

//---------- MainWindow ----------//

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
      d(new Internal::MainWindowPrivate(this))
{
}

MainWindow::~MainWindow()
{
}

void MainWindow::closeEvent(QCloseEvent *event)
{
//    if (maybeSave()) {
        AppContext::instance()->shutdown();
        event->accept();
//    } else {
//        event->ignore();
//    }
}
